import copy
import math
import random
import mwmatching

__author__="kamillo"
__date__ ="$2009-10-31 13:34:48$"


class SVQ:
    def __init__(self,N,Data,Beta,eta):
        self.N = N
        self.Data = Data
        self.Beta = Beta
        self.m = []
        self.eta = eta
        self.log = []
        

    def initCodeBook(self,dim,fromdata = True,wrange = [0,300], hrange = [0,300]):
        wrange.sort()
        hrange.sort()
        if fromdata:
            while len(self.m)<self.N:
                self.m.append([])
                for i in range(dim):
                    cand = self.Data[random.randint(0,len(self.Data)-1)]
                    if  wrange[0] <= cand[0] <= wrange[1] and hrange[0] <= cand[1] <= hrange[1] :
                        self.m[-1].append(cand)
        else:
            self.m = [ [[random.randint(wrange[0],wrange[1]),random.randint(hrange[0],hrange[1])] for i in range(dim)] for j in range(self.N) ]
        #print self.m
        return self.m

    def initCodeBook2(self):
        rand = []
        while len(self.m) < self.N:
            r = random.randint(0,len(self.Data)-1)
            print r
            if r not in rand:
                self.m.append(self.Data[r])
                rand.append(r)
        return self.m


    
    def pickDataPoint(self):
        i = random.randint(0,len(self.Data)-1)
        return [self.Data[i]]

    def pickData(self):
        i = random.randint(0,len(self.Data)-1)
        return self.Data[i]
    
    def calcF(self,x):
        Beta = self.Beta
        self.x = x
        Sum = []
        for j in self.m:
            tmp_sum = 0
            for point in range(len(x)):
                for cord in range(len(x[point])):
                    tmp_sum += ( x[point][cord] -  j[point][cord] )**2
                    #print 'tmp_sum', tmp_sum,x[point][cord],j[point][cord]
            Sum.append(math.exp( -Beta * tmp_sum))
        sum_ = sum(Sum)
        #if len(self.m) == 4:
        #    print 'sum_ Sum ',sum_, Sum
        F = [Sum[i]/sum_ for i in range(len(self.m))]
        return F

    def moveCodeBook(self,F):
        x = self.x
        m = self.m
        eta = self.eta
        przes = []
        for i in range(self.N):
            for point in range(len(x)):
                for cord in range(len(x[point])):
                    #print 'svq',F[i],eta * ( x[point][cord] - m[i][point][cord] ) * F[i]
                    m[i][point][cord] = m[i][point][cord] + eta * ( x[point][cord] - m[i][point][cord] ) * F[i]
        #self.log.append(przes)
        return m
    def moveImgCodeBook(self,F):
        x = self.x
        m = self.m
        eta = self.eta
        distances = []
        for i in range(self.N):
            distances.append([])
            for cpoint in m[i]:
                distances[-1].append([])
                for point in self.x:
                    distances[-1][-1].append([(point[0]-cpoint[0])**2+(point[1]-cpoint[1])**2,x.index(point)]) #distances[nr_ImgCodeBook][nr_CodeBook][dist,nr_DataImagePoint]
                #distances[-1][-1].sort()
                #print distances[-1][-1]
            graph = [] # [ (cpi,len(m[i])+distances[i][0],) for cpi in range(len(distances[i])) ]
            for cpi in range(len(distances[i])):
                for xi in range(len(distances[i][cpi])):
                    graph.append((cpi,len(m[i])+distances[i][cpi][xi][1],-int(1000*distances[i][cpi][xi][0])))

        #for g in graph:
        #    print g[2]
            minmatch = mwmatching.maxWeightMatching(graph,maxcardinality=True)
        #for i in range(self.N):
            for point in range(len(x)):
                for cord in range(len(x[point])):
                    #print 'svq',F[i],eta * ( x[point][cord] - m[i][point][cord] ) * F[i]
                    m[i][point][cord] = (
                    m[i][point][cord] +
                    eta *
                    ( x[minmatch[point]
                    -len(m[i])][cord]
                    - m[i][point][cord] )
                    * F[i])
        #self.log.append(przes)
        return m
    """
        def moveImgCodeBook(self,F):
            x = self.x
            m = self.m
            #print self.m
            eta = self.eta
            distances = []
            sorteddistances = []

            for i in range(self.N):
                distances.append([])
                for cpoint in m[i]:
                    distances[-1].append([])
                    for point in self.x:
                        #if (point[0]-cpoint[0])**2+(point[1]-cpoint[1])**2 == 0.0:
                        #    print i, point[0],point[1],cpoint[0],cpoint[1]
                        distances[-1][-1].append([(point[0]-cpoint[0])**2+(point[1]-cpoint[1])**2,x.index(point)]) #distances[nr_ImgCodeBook][nr_CodeBook][dist,nr_DataImagePoint]
                    distances[-1][-1].sort()

                sorteddistances = [ [copy.copy(distances[i][j][k]) for j in range(len(distances[i]))] for k in range(len(distances[i][0])) ]
                sorteddistances.sort()
                tmp = []
                for j in range(len(sorteddistances[0])):
                    for level in range(len(sorteddistances)):
                        if sorteddistances[level][j][1] not in tmp:
                        #    print 'dodaje do',i, sorteddistances[level][j][1], ' z poziomu ', level
                            tmp.append(sorteddistances[level][j][1])
                            break;
                        #else: print'juz jest',sorteddistances[level][j][1]


                    #print x
                    #print m[i]
                    #print distances[-1][-1]

                for point in range(len(x)):
                    for cord in range(len(x[point])):
                        #print i, F[i], eta * ( x[distances[i][point][0][1]][cord] - m[i][point][cord] ) * F[i]
                        #x[distances[i][point][0][1]][cord]
                        try:
                            cos = x[tmp[point]][cord]
                        except IndexError:
                            print point, cord, i, len(tmp), tmp
                        m[i][point][cord] =  m[i][point][cord] + eta * (cos - m[i][point][cord] ) * F[i]
            return m


    """
    def saveLog(self,fname):
        file = open('/tmp/'+str(fname),'a')
        for line in self.log:
            for l in line:
                file.write(str(l)+'\t')
            file.write('\n')
        file.close()
                    


